package test
{
	import binPack.Node;
	import binPack.binaryTree.BinaryTreeBinPacker;
	import binPack.guillotine.FreeRectChoiceHeuristic;
	import binPack.guillotine.GuillotineBinPack;
	import binPack.guillotine.GuillotineSplitHeuristic;
	import binPack.maxRect.FreeRectChoiceHeuristic;
	import binPack.maxRect.MaxRectsBinPack;
	import binPack.shelf.ShelfBinPack;
	import binPack.shelfNextFit.ShelfNextFitBinPack;
	import binPack.skylineBinPack.LevelChoiceHeuristic;
	import binPack.skylineBinPack.SkylineBinPack;
	
	import com.bit101.components.ComboBox;
	import com.bit101.components.PushButton;
	
	import flash.desktop.ClipboardFormats;
	import flash.desktop.NativeDragManager;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.NativeDragEvent;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.geom.Rectangle;
	import flash.utils.ByteArray;
	
	public class BinPackTest extends Sprite
	{
		public function BinPackTest()
		{
			super();
			initBg();
			if(this.stage){
				this.init();
			}else{
				this.addEventListener(Event.ADDED_TO_STAGE, init);
			}
			combo = new ComboBox(this,5,5,'',['MaxRect','Guillotine','Shelf','ShelfNextFit','Skyline','BinaryTree']);
			combo.selectedIndex = 0;
			packBtn = new PushButton(this,5,30,'PACK',onPack);
		}
		
		private var packBins:Object = {
			'MaxRect':new MaxRectsBinPack(1024,1024),
			'Guillotine':new GuillotineBinPack(1024,1024),
			'Shelf':new ShelfBinPack(1024,1024),
			'ShelfNextFit':new ShelfNextFitBinPack(1024,1024),
			'Skyline':new SkylineBinPack(1024,1024)
		};
		
		private var combo:ComboBox;
		private var packBtn:PushButton;
		private function initBg():void{
			packArea = new Sprite();
			this.bg = new Bitmap(new BitmapData(1200,800,false,0xcccccc));
			this..addChild( bg );
			bg.x = 110;
			packArea.x = 110;
			this.addChild(packArea);
		}
		
		private function init(evt:Event=null):void{
			if( evt != null ){
				this.removeEventListener(Event.ADDED_TO_STAGE, init);
			}
			drawBg();
			this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onDragEnter);
			this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onDragDrop);
			this.addEventListener(NativeDragEvent.NATIVE_DRAG_EXIT, onDragExit);
			this.addEventListener(NativeDragEvent.NATIVE_DRAG_COMPLETE, onDragComplete);
		}
		
		private function onDragEnter(evt:NativeDragEvent):void{
			if(evt.clipboard.hasFormat(ClipboardFormats.FILE_LIST_FORMAT))
			{
				//get the array of files
				var files:Array = evt.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
			
				//accept the drag action
				NativeDragManager.acceptDragDrop(this);
			}
		}
		private var total:int;
		private var complete:int;
		private function onDragDrop(evt:NativeDragEvent):void{
			var arr:Array = evt.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
			var file:File;
			var fs:FileStream;
			total = arr.length;
			var ba:ByteArray;
			var loader:Loader;
			for(var i:int = 0; i < total; i++){
				//grab the files file
				file = File(arr[i]);
				if( file.extension != "png" && file.extension != "jpg"){
					complete++;
					continue;
				}
				ba = new ByteArray();
				fs = new FileStream();
				fs.open(file, FileMode.READ); 
				fs.readBytes(ba);
				loader = new Loader();
				loader.name = file.name;
				loader.loadBytes(ba);
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
			}
		}
		private var imageMap:Object = {};
		private var packInfo:Object = {};
		private var packBin:*;
		private var ready:Boolean;
		private function onImageLoaded(evt:Event):void{
			trace('load progress:',complete,'/',total);
			var loader:Loader = (evt.target as LoaderInfo).loader;
			imageMap[loader.name] = loader.content;
			packArea.addChild(loader.content);
			complete++;
			ready = complete == total;
		}
		private function onPack(evt:MouseEvent):void{
			var label:String = String(combo.selectedItem);
			trace('use '+label+' do the pack');
			if( label == "BinaryTree"){
				binaryTreePack();
				return;
			}
			
			packBin = packBins[label];
			//packBin.Init(1024,1024);
			var image:Bitmap;
			var rectWidth:int;
			var rectHeight:int;
			var packRect:*;
			for(var key:String in imageMap){
				image = imageMap[key];
				rectWidth = image.width;
				rectHeight = image.height;
				if( packBin is MaxRectsBinPack){
					packRect = MaxRectsBinPack(packBin).Insert(rectWidth, rectHeight, binPack.maxRect.FreeRectChoiceHeuristic.RectBestShortSideFit);
				}else if(packBin is GuillotineBinPack){
					packRect = GuillotineBinPack(packBin).Insert(rectWidth, rectHeight, true, 
						binPack.guillotine.FreeRectChoiceHeuristic.RectBestAreaFit,
						binPack.guillotine.GuillotineSplitHeuristic.SplitMinimizeArea);
				}else if( packBin is ShelfBinPack){
					packRect = ShelfBinPack(packBin).Insert(rectWidth, rectHeight, binPack.shelf.ShelfChoiceHeuristic.ShelfBestAreaFit);
				}else if( packBin is ShelfNextFitBinPack){
					packRect = ShelfNextFitBinPack(packBin).Insert(rectWidth, rectHeight);
				}else if( packBin is SkylineBinPack){
					packRect = SkylineBinPack(packBin).Insert(rectWidth, rectHeight, binPack.skylineBinPack.LevelChoiceHeuristic.LevelBottomLeft);
				}
				
				if (packRect && packRect.height > 0){
					packInfo[key] = packRect;
					image.x = packRect.x;
					image.y = packRect.y;
					image.width = packRect.width;
					image.height = packRect.height;
					if( packRect.hasOwnProperty('flipped')){
						trace(packRect['flipped']);
					}
					trace("Packed to (x,y:"+packRect.x+","+packRect.y+")=(w,h:"+packRect.width+","+ packRect.height+"), Free space left:"+ (100 - packBin.Occupancy()*100)+"%\n");
				}
				else
					trace("Failed! Could not find a proper position to pack this rectangle into. Skipping this one.\n");
				
			}
			trace("Done. All rectangles packed.\n");
		}
		private function binaryTreePack():void{
			var arr:Vector.<Bitmap> = new Vector.<Bitmap>();
			for(var key:String in imageMap){
				arr.push(imageMap[key]);
			}
			var packer:BinaryTreeBinPacker = new BinaryTreeBinPacker(1024,1024);
			packer.fit(arr);
			trace("BinaryTree Pack Done");
		}
		private function onDragExit(evt:NativeDragEvent):void{
			trace(evt.type);
		}
		private function onDragComplete(evt:NativeDragEvent):void{
			trace(evt.type);
		}
		private var packArea:Sprite;
		private var bg:Bitmap;
		private function drawBg():void{
			
			bg.width = this.stage.width;
			bg.height = this.stage.height;
		}
	}
}